//******************************************************************************
/**
 *
 * @file	slot_sub.c
 * @brief	ミニゲーム　スロット　サブ
 * @author	iwasawa
 * @data	08.11.28
 *
 */
//******************************************************************************
#include "common.h"
#include "system/procsys.h"
#include "system/bmp_list.h"
#include "system/bmp_menu.h"
#include "system/arc_util.h"
#include "system/arc_tool.h"
#include "system/snd_tool.h"
#include "system/fontproc.h"
#include "system/pm_str.h"
#include "system/msgdata.h"
#include "system/buflen.h"
#include "system/window.h"
#include "system/brightness.h"
#include "system/clact_util.h"
#include "system/clact_tool.h"
#include "system/render_oam.h"
#include "system/palanm.h"
#include "system/wipe.h"
#include "system/window.h"
#include "system/font_arc.h"
#include "system/winframe.naix"
#include "gflib/touchpanel.h"
#include "gflib/strbuf_family.h"

#include "application/app_tool.h"

#include "slot_local.h"
#include "slot_sub.h"
#include "slot_reel.h"

//=====================================================================
//リテラル定義
//=====================================================================
#define COIN_NUM_KETA		(5)

#define BGS_COIN_NUM_WY		(18)
#define BGS_COIN_NUM_WX1	(14)
#define BGS_COIN_NUM_WX2	(27)
#define BGS_COIN_NUM_SX		(1)
#define BGS_COIN_NUM_SY		(2)

#define GUIDE_PAYOUT_KETA	(2)
#define GUIDE_ROUND_KETA	(2)
#define GUIDE_COIN_KETA		(3)

#define BGS_GUIDE_WX		(1)
#define BGS_GUIDE_WY		(19)
#define BGS_GUIDE_PX		(0)
#define BGS_GUIDE_SX		(29)
#define BGS_GUIDE_SY		(4)
#define BGS_GUIDE_N_PY		(6)
#define BGS_GUIDE_B_PY		(BGS_GUIDE_N_PY+BGS_GUIDE_SY)

#define BGS_NGUIDE_ONE_SX	(9)
#define BGS_NGUIDE_ONE_SY	(2)
#define BGS_NGUIDE_OX		(BGS_NGUIDE_ONE_SX+1)
#define BGS_NGUIDE_OY		(BGS_NGUIDE_ONE_SY)
#define BGS_NGUIDE_BLANK_DX	(21)
#define BGS_NGUIDE_BLANK_DY	(14)

#define BGS_GNUM_SX			(1)
#define BGS_GNUM_SY			(2)
#define BGS_GNUM_PX			(0)
#define BGS_GNUM_PY			(0)

#define BGS_BIG_WX			(7)
#define BGS_REG_WX			(BGS_BIG_WX)

#define BGS_ROUND_WX		(9)
#define BGS_ROUND_MAX_WX	(12)
#define BGS_GET_WX			(7)

#define BGS_GPOKE_WX		(18)
#define BGS_GPOKE_WY		(BGS_GUIDE_WY)
#define BGS_GPOKE_PX		(0)
#define BGS_GPOKE_PY		(14)
#define BGS_GPOKE_SX		(4)
#define BGS_GPOKE_SY		(4)

#define BGS_GPAYOUT_WX		(BGS_GPOKE_WX+BGS_GPOKE_SX+1)
#define BGS_GPAYOUT_SX		(2)
#define BGS_GPAYOUT_SY		(4)
#define BGS_GPAYOUT_PY		(2)

#define BGS_GGET_WX			(7)
#define BGS_GGET_WY			(BGS_GUIDE_WY+2)

#define BGS_PICT_WX			(13)
#define BGS_PICT_WY			(9)
#define BGS_PICT_SX			(6)
#define BGS_PICT_SY			(6)

#define BGWIN_PICT_X	(BGS_PICT_WX*8)
#define BGWIN_PICT_Y	(BGS_PICT_WY*8)
#define BGWIN_PICT_W	(BGS_PICT_SX*8)
#define BGWIN_PICT_H	(BGS_PICT_SY*8)

#define BETLINE_COL_ON	(1)
#define BETLINE_COL_OFF	(0)
#define REEL_LAMP_COL_ON	(1)
#define REEL_LAMP_COL_OFF	(0)

#define PANM_BETLINE_IDX	(1)
#define PANM_BETLINE_CNUM	(2)
#define PANM_BETLINE_COFS	(0xB)
#define PANM_BETLINE_SIDX	(0xA)

#define PANM_REEL_LAMP_IDX	(6)
#define PANM_REEL_LAMP_CNUM	(2)
#define PANM_REEL_LAMP_COFS	(0x0b)
#define PANM_REEL_LAMP_SIDX	(0x0A)

#define PANM_GUIDE_IDX	(6)
#define PANM_GUIDE_CNUM	(14)
#define PANM_GUIDE_COFS	(2)
#define PANM_GUIDE_COL	(0x14a5)

#define PANM_REEL_IDX	(1)
#define PANM_REEL_CNUM	(16*6)
#define PANM_REEL_COL	(0x7FFF)

#define PANM_DRAFT_IDX	(7)
#define PANM_DRAFT_COL	(0x6b5a)
#define PANM_DRAFT_CNUM	(16)
#define PANM_PICT_CNUM	(16)
#define PANM_PICT_IDX	(8)

#define ICON_CX	(ACT_DBR_PX-12)
#define ICON_CY	(ACT_DBR_PY-32)

#define EM_ICON_EFF_TIME	(16)

#define EM_ICON_OX1	(0)
#define EM_ICON_OX2	(20)
#define EM_ICON_OX3	(28)
#define EM_ICON_OX4	(48)

#define EM_ICON_Y1	(ICON_CY-4)
#define EM_ICON_Y2	(EM_ICON_Y1-24)

//=====================================================================
//プロトタイプ定義
//=====================================================================
static void sub_GuideNormalBlankDraw( SLOTMAIN* wk,PRIZE_CODE code);
static void sub_GuidePokeDraw( SLOTMAIN* wk, BONUS_CODE bonus_code);
static void sub_GuidePayoutNumDraw( SLOTMAIN* wk ,int payout);
static void sub_GuideNumDraw( SLOTMAIN* wk ,int num , int keta_max, u8 wx,u8 wy );
static int get_num_keta(u32 num,u8 keta);

//=====================================================================
//データ定義
//=====================================================================

///////////////////////////////////////////////////////////////////////
//=====================================================================
//グローバル関数定義
//=====================================================================
///////////////////////////////////////////////////////////////////////

/**
 *	@brief	乱数取得(1000で割った余りを返す)
 */
u16 SlotSub_Rand1000(void)
{
	return gf_rand()%1000;
}

/**
 *	@brief	乱数取得
 */
u16 SlotSub_Rand(int div)
{
	if(div == 2){
		return (gf_rand()%1000)/500;	//偏らないようにしてる
	}
	return gf_rand()%div;
}

/**
 *	@brief	単純入力チェック
 */
BOOL SlotSub_InputCheck( SLOTMAIN* wk )
{
	if(sys.trg & PAD_BUTTON_A){
		wk->key_mode = APP_KTST_KEY;
		return TRUE;
	}else if(GF_TP_GetTrg()){
		wk->key_mode = APP_KTST_TOUCH;
		return TRUE;
	}
	return FALSE;
}

/**
 *	@brief	役がREGまたはビックか？
 */
BOOL SlotSub_IsBonusCode( int prize_code )
{
	if(prize_code == PRIZE_BIG || prize_code == PRIZE_REG){
		return TRUE;
	}
	return FALSE;
}

/**
 *	@brief	払い戻しコイン数取得
 */
int SlotSub_GetPayoutCoinNum( SLOTMAIN* wk, int code)
{
	static const u8 PayoutTbl[] = {
		COIN_PAYOUT_ZERO,COIN_PAYOUT_REPLAY,COIN_PAYOUT_PIKA,
		COIN_PAYOUT_MARIRU,COIN_PAYOUT_BONG,COIN_PAYOUT_BONUS,COIN_PAYOUT_BONUS};
	static const u8 BonusPayoutTbl[]  = {
		COIN_PAYOUT_CHIKO,COIN_PAYOUT_HINO,COIN_PAYOUT_WANI
	};

	if(wk->bonus_game_f){
		IWASAWA_PRINT("BonusPayout = %d win_ct=%d,concec=%d,pay=%d\n",
			BonusPayoutTbl[code]+((wk->bonus_win_ct/2) * (1+(wk->consec_win/4))),
			wk->bonus_win_ct,wk->consec_win,BonusPayoutTbl[code]
				);
		return BonusPayoutTbl[code]	+
			((wk->bonus_win_ct/2) * (1+(wk->consec_win/4)));
	}else{
		if( SlotSub_IsBonusCode(code)){
			return PayoutTbl[code]+wk->bonus_credit[code-PRIZE_REG];
		}
		return PayoutTbl[code];
	}
}

/**
 *	@brief	戻るボタン描画
 */
void SlotSub_BackBtnWrite(SLOTMAIN* wk,BACK_BTN_MODE mode)
{
	if(mode == BACK_BTN_ACTIVE){
		wk->back_btn_passive_f = FALSE;
	}else{
		wk->back_btn_passive_f = TRUE;
	}
	CLACT_AnmChg( wk->pAct[ACT_BACK], ANMD_BACK + mode );
	CLACT_AnmReStart( wk->pAct[ACT_BACK]);
}

/*
 *	@brief	ウィンドウメッセージ出力
 */
void SlotSub_WinMsgPut(SLOTMAIN* wk,MIDX_WIN idx)
{
	BmpTalkWinWrite( &wk->win[WIN_MSG],
		WINDOW_TRANS_OFF, BMP_TALK_WIN_CGX, BMP_TALK_WIN_PAL);

	GF_BGL_BmpWinDataFill( & wk->win[WIN_MSG], FBMP_COL_WHITE );

	MSGMAN_GetString(wk->msg.man,msg_win00+idx,wk->msg.str);

	GF_STR_PrintColor( &wk->win[WIN_MSG], FONT_TALK, wk->msg.str,
			0,0, MSG_NO_PUT, FCOL_WIN_W_BLACK, NULL );

	GF_BGL_BmpWinOnVReq(&wk->win[WIN_MSG]);
}

/**
 *	@brief	ウィンドウメッセージクリア
 */
void SlotSub_WinMsgClear(SLOTMAIN* wk)
{
	BmpTalkWinClear( &wk->win[WIN_MSG], WINDOW_TRANS_OFF);
	GF_BGL_BmpWinDataFill( & wk->win[WIN_MSG], 0 );
	GF_BGL_BmpWinOffVReq( &wk->win[WIN_MSG]);
	GF_BGL_LoadScreenV_Req( wk->bgl, DFRM_MSG );
}

/**
 *	@brief	システムメッセージ出力
 */
void SlotSub_SysMsgPut(SLOTMAIN* wk,MIDX_SYS idx)
{
	GF_BGL_BmpWinDataFill( & wk->win[WIN_EXP], FCOL_SYS_BLACK );

	MSGMAN_GetString(wk->msg.man,msg_exp01+idx,wk->msg.str);

	GF_STR_PrintColor( &wk->win[WIN_EXP], FONT_SYSTEM, wk->msg.str,
			0,0, MSG_NO_PUT, FCOL_SYS_B_GREEN, NULL );

	GF_BGL_BmpWinOnVReq(&wk->win[WIN_EXP]);
}

/**
 *	@brief	ドーブルアニメ切替
 */
void SlotSub_DooburuAnmSet( SLOTMAIN* wk, DOOBURU_STATE state )
{
	CLACT_AnmChg( wk->pAct[ACT_POKE], ANMU_DBR_F+state );
	CLACT_AnmReStart( wk->pAct[ACT_POKE] );
}

/**
 *	@brief	下画面数値出力
 */
void SlotSub_CoinNumDraw(SLOTMAIN* wk,int num,COIN_NUM_MODE mode)
{
	int i,en_f,keta,pos;
	u8 write_pos[] = {BGS_COIN_NUM_WX1,BGS_COIN_NUM_WX2};

	en_f = 0;
	for(i = COIN_NUM_KETA-1;i >= 0 ;i--){
		keta = get_num_keta(num,i);

		if(keta){
			en_f = 1;
		}
		if(en_f){
			pos = keta+2;
		}else if(keta == 0 && i == 0){
			pos = 2;
		}else{
			pos = 0;
		}
		GF_BGL_ScrWriteExpand(wk->bgl,DFRM_MECH,
			write_pos[mode]-(i*BGS_COIN_NUM_SX),BGS_COIN_NUM_WY,
			BGS_COIN_NUM_SX,BGS_COIN_NUM_SY,
			wk->sd_num.dat,pos,0,
			wk->sd_num.siz_x,wk->sd_num.siz_y);

	}
	GF_BGL_LoadScreenV_Req(wk->bgl,DFRM_MECH);
}

/**
 *	@brief	上画面ガイド　出力
 */
void SlotSub_GuideBaseDraw( SLOTMAIN* wk, GAME_STATE state)
{
	u8 x,y;

	if(state == STATE_NORMAL){
		y = BGS_GUIDE_N_PY;
	}else{
		y = BGS_GUIDE_B_PY;
	}
	GF_BGL_ScrWriteExpand( wk->bgl, UFRM_GUIDE,
		BGS_GUIDE_WX, BGS_GUIDE_WY, BGS_GUIDE_SX, BGS_GUIDE_SY,
		wk->su_guide.dat,BGS_GUIDE_PX, y,
		wk->su_guide.siz_x,wk->su_guide.siz_y);

	SlotSub_GuideParamDraw( wk , state, BONUS_BLANK );
	GF_BGL_LoadScreenV_Req(wk->bgl,UFRM_GUIDE);
}

/**
 *	@brief	上画面ガイド　パラメータ出力
 */
void SlotSub_GuideParamDraw( SLOTMAIN* wk ,GAME_STATE state, BONUS_CODE bonus_code)
{
	if(state == STATE_NORMAL){
		sub_GuideNumDraw( wk,
				COIN_PAYOUT_BONUS+wk->bonus_credit[REACH_BIG],
				GUIDE_COIN_KETA, BGS_BIG_WX, BGS_GUIDE_WY );
		sub_GuideNumDraw( wk,
				COIN_PAYOUT_BONUS+wk->bonus_credit[REACH_REG],
				GUIDE_COIN_KETA, BGS_REG_WX, BGS_GUIDE_WY + BGS_GNUM_SY);
	}else{
		sub_GuidePokeDraw( wk, bonus_code);
		sub_GuideNumDraw( wk , wk->bonus_round+1 , GUIDE_ROUND_KETA, BGS_ROUND_WX, BGS_GUIDE_WY );
		sub_GuideNumDraw( wk , wk->bonus_round_max , GUIDE_ROUND_KETA, BGS_ROUND_MAX_WX, BGS_GUIDE_WY );
		sub_GuideNumDraw( wk , wk->bonus_get_ct , GUIDE_COIN_KETA, BGS_GET_WX, BGS_GUIDE_WY+BGS_GNUM_SY );
	}
	GF_BGL_LoadScreenV_Req(wk->bgl,UFRM_GUIDE);
}

/**
 *	@brief	上画面ガイド　ノーマルモードブランク絵表示
 */
static void sub_GuideNormalBlankDraw( SLOTMAIN* wk,PRIZE_CODE code)
{
	u8 g_idx;
	s16 px,py;

	//プライズコード→ガイド配置index変換
	static const u8 guide_tbl[] = {5,4,2,1,3,0};
	g_idx = guide_tbl[code-1];

	px = ((g_idx%3)*BGS_NGUIDE_OX)+BGS_GUIDE_WX;
	py = ((g_idx/3)*BGS_NGUIDE_OY)+BGS_GUIDE_WY;

	GF_BGL_ScrWriteExpand( wk->bgl, UFRM_GUIDE,
		px, py, BGS_NGUIDE_ONE_SX, BGS_NGUIDE_ONE_SY,
		wk->su_guide.dat,BGS_NGUIDE_BLANK_DX, BGS_NGUIDE_BLANK_DY,
		wk->su_guide.siz_x,wk->su_guide.siz_y);
}

/**
 *	@brief	上画面ガイド　抽選絵表示
 */
static void sub_GuidePokeDraw( SLOTMAIN* wk, BONUS_CODE bonus_code)
{
	u16 sx = BGS_GPOKE_SX;

	GF_BGL_ScrWriteExpand( wk->bgl, UFRM_GUIDE,
		BGS_GPOKE_WX, BGS_GPOKE_WY, sx, BGS_GPOKE_SY,
		wk->su_guide.dat,BGS_GPOKE_PX+(bonus_code*BGS_GPOKE_SX), BGS_GPOKE_PY,
		wk->su_guide.siz_x,wk->su_guide.siz_y);

	if(bonus_code == BONUS_BLANK){
		sub_GuidePayoutNumDraw( wk , 0 );
	}else{
		sub_GuidePayoutNumDraw( wk , wk->bonus_payout );
	}
}

/**
 *	@brief	上画面ガイド　ボーナス払い出しコイン数出力
 */
static void sub_GuidePayoutNumDraw( SLOTMAIN* wk ,int payout)
{
	int i,keta,pos;
	int en_f = 0;

	for(i = 0;i < GUIDE_PAYOUT_KETA;i++){
		keta = get_num_keta(payout,(GUIDE_PAYOUT_KETA-1)-i);

		if(keta){
			en_f = 1;
		}
		if(en_f){
			pos = keta+1;
		}else if(keta == 0 && i == (GUIDE_PAYOUT_KETA-1) && (payout != 0)){
			pos = 1;
		}else{
			pos = 0;
		}
		GF_BGL_ScrWriteExpand(wk->bgl,UFRM_GUIDE,
			BGS_GPAYOUT_WX+(BGS_GPAYOUT_SX*i),BGS_GUIDE_WY,
			BGS_GPAYOUT_SX,BGS_GPAYOUT_SY,
			wk->su_guide.dat,(pos*BGS_GPAYOUT_SX),BGS_GPAYOUT_PY,
			wk->su_guide.siz_x,wk->su_guide.siz_y);
	}
}

/**
 *	@brief	上画面ガイド　パラメータ数出力
 */
static void sub_GuideNumDraw( SLOTMAIN* wk ,int num , int keta_max, u8 wx,u8 wy )
{
	int i,keta,pos;

	for(i = 0;i < keta_max;i++){
		keta = get_num_keta(num,(keta_max-1)-i);

		GF_BGL_ScrWriteExpand(wk->bgl,UFRM_GUIDE,
			wx+(BGS_GNUM_SX*i),wy,
			BGS_GNUM_SX,BGS_GNUM_SY,
			wk->su_guide.dat,(keta+1)*BGS_GNUM_SX,BGS_GNUM_PY,
			wk->su_guide.siz_x,wk->su_guide.siz_y);
	}
}

////////////////////////////////////////////////////////////////////////
/**
 *	@brief	上画面ガイド切替エフェクト
 */
////////////////////////////////////////////////////////////////////////

typedef struct _TASKWK_GUIDE_CHANGE{
	int* tcb_ct;	//タスクの終了を検知するためのカウンタ。TRUEなら再生中。NULL可

	int	seq;
	int	state;
	int evy;
	SLOTMAIN* psm;
}TASKWK_GUIDE_CHANGE;

static void tcb_GuideChangeTask( TCB_PTR tcb, void* p_work );

/**
 *	@brief	上画面ガイド描画切替エフェクトタスクセット
 *
 *	@param	tcb_ct	タスクの動作数を監視するカウンタへのポインタ(NULL指定可)
 *	@param	pri	タスクの動作プライオリティ
 *
 *	tcb_ctへのポインタは、渡しておくとタスク追加時に +1し、タスクを削除するときに -1します
 */
TCB_PTR AddTCB_GuideChange(SLOTMAIN* wk,GAME_STATE next_state,int* tcb_ct,u8 pri)
{
	TASKWK_GUIDE_CHANGE* tp;

	tp = sys_AllocMemory(wk->heapID,sizeof(TASKWK_GUIDE_CHANGE));
	MI_CpuClear8(tp,sizeof(TASKWK_GUIDE_CHANGE));

	tp->state = next_state;

	tp->psm = wk;
	tp->tcb_ct = tcb_ct;

	if(tp->tcb_ct != NULL){
		(*tp->tcb_ct)++;
	}
	return TCB_Add( tcb_GuideChangeTask, tp, pri);
}

/**
 *	@brief	ガイドチェンジ
 */
static void tcb_GuideChangeTask( TCB_PTR tcb, void* p_work )
{
	TASKWK_GUIDE_CHANGE* tp = (TASKWK_GUIDE_CHANGE*)p_work;
	SLOTMAIN* wk = tp->psm;

	switch(tp->seq){
	case 0:
		SoftFadePfd(wk->palAnm,FADE_MAIN_BG,
			(PANM_GUIDE_IDX*16) + PANM_GUIDE_COFS,
			PANM_GUIDE_CNUM,tp->evy,PANM_GUIDE_COL);
		if(tp->evy++ < 16){
			break;
		}
		SlotSub_GuideBaseDraw( wk, tp->state );
		tp->seq++;
		break;
	case 1:
		SoftFadePfd(wk->palAnm,FADE_MAIN_BG,
			(PANM_GUIDE_IDX*16) + PANM_GUIDE_COFS,
			PANM_GUIDE_CNUM,tp->evy,PANM_GUIDE_COL);
		if(tp->evy-- > 0){
			break;
		}
	default:
		if(tp->tcb_ct != NULL){
			(*tp->tcb_ct) -= 1;
		}
		sys_FreeMemoryEz(p_work);
		TCB_Delete( tcb );
		tcb = NULL;
		return;
	}
}

////////////////////////////////////////////////////////////////////////
/**
 *	@brief	リール表示切替エフェクト
 */
////////////////////////////////////////////////////////////////////////

typedef struct _TASKWK_REEL_CHANGE{
	int* tcb_ct;	//タスクの終了を検知するためのカウンタ。TRUEなら再生中。NULL可

	int seq;
	int	state;
	int evy;
	SLOTMAIN* psm;
}TASKWK_REEL_CHANGE;

static void tcb_ReelChangeTask( TCB_PTR tcb, void* p_work );

/**
 *	@brief	リール絵切替エフェクトタスクセット
 *
 *	@param	tcb_ct	タスクの動作数を監視するカウンタへのポインタ(NULL指定可)
 *	@param	pri	タスクの動作プライオリティ
 *
 *	tcb_ctへのポインタは、渡しておくとタスク追加時に +1し、タスクを削除するときに -1します
 */
TCB_PTR AddTCB_ReelChange(SLOTMAIN* wk,int* tcb_ct,u8 pri)
{
	TASKWK_REEL_CHANGE* tp;

	tp = sys_AllocMemory(wk->heapID,sizeof(TASKWK_REEL_CHANGE));
	MI_CpuClear8(tp,sizeof(TASKWK_REEL_CHANGE));

	tp->psm = wk;
	tp->tcb_ct = tcb_ct;

	if(tp->tcb_ct != NULL){
		(*tp->tcb_ct)++;
	}
	return TCB_Add( tcb_ReelChangeTask, tp, pri);
}

/**
 *	@brief	リール絵チェンジ
 */
static void tcb_ReelChangeTask( TCB_PTR tcb, void* p_work )
{
	TASKWK_REEL_CHANGE* tp = (TASKWK_REEL_CHANGE*)p_work;
	SLOTMAIN* wk = tp->psm;

	switch(tp->seq){
	case 0:
		SoftFadePfd(wk->palAnm,FADE_SUB_OBJ,
			(PANM_REEL_IDX*16),	PANM_REEL_CNUM,tp->evy,PANM_REEL_COL);
		if(++tp->evy < 16){
			break;
		}
		SlotReel_PosInit( wk );
		SlotReel_ViewInit( wk );
		tp->seq++;
		break;
	case 1:
		SoftFadePfd(wk->palAnm,FADE_SUB_OBJ,
			(PANM_REEL_IDX*16),PANM_REEL_CNUM,tp->evy,PANM_REEL_COL);
		if(--tp->evy > 0){
			break;
		}
	default:
		if(tp->tcb_ct != NULL){
			(*tp->tcb_ct) -= 1;
		}
		sys_FreeMemoryEz(p_work);
		TCB_Delete( tcb );
		tcb = NULL;
		return;
	}
}

/**
 *	@brief	ベットライン点灯状態制御
 */
static void sub_BetLineColorSet( SLOTMAIN* wk, LINE_CODE line, u16 evy)
{
	u16 read_pos;
	static const u8 col_tbl[LINE_CODE_MAX] = {1,0,1,2,2};

	read_pos = (PANM_BETLINE_CNUM*col_tbl[line])+(PANM_BETLINE_SIDX+evy)*16+1;

	PaletteWorkSet( wk->palAnm,
		&(wk->pu_back.dat[read_pos]),FADE_SUB_BG,
		(PANM_BETLINE_IDX+line)*16+PANM_BETLINE_COFS,
		2*PANM_BETLINE_CNUM );
#if 0
	SoftFadePfd(wk->palAnm,FADE_SUB_BG,
		((PANM_BETLINE_IDX+line)*16) + PANM_BETLINE_COFS,
		PANM_BETLINE_CNUM,evy,0x7FFF);
#endif
}

/**
 *	@brief	ベットライン点灯/消灯セット
 */
void SlotSub_BetLineLightSet( SLOTMAIN* wk, LINE_CODE line, LIGHT_STATE st)
{
	sub_BetLineColorSet( wk, line, st);
}

/**
 *	@brief	ベットライン
 */
void SlotSub_BetLineLightSetAll( SLOTMAIN* wk, LIGHT_STATE st)
{
	int i;

	for(i = 0;i < LINE_CODE_MAX;i++){
		SlotSub_BetLineLightSet( wk, i, st);
	}
}

/**
 *	@brief	リール停止ランプカラーセット
 */
static void sub_ReelLampColorSet( SLOTMAIN* wk, REEL_NUM no, u16 evy)
{
	u16 read_pos;

	read_pos = (PANM_REEL_LAMP_CNUM*(2-no))+(PANM_REEL_LAMP_SIDX+evy)*16+1;

	PaletteWorkSet( wk->palAnm,
		&(wk->pu_back.dat[read_pos]),FADE_SUB_BG,
		(PANM_REEL_LAMP_IDX+no)*16+PANM_REEL_LAMP_COFS,
		2*PANM_REEL_LAMP_CNUM );
#if 0
	SoftFadePfd(wk->palAnm,FADE_SUB_BG,
		((PANM_REEL_LAMP_IDX+no)*16) + PANM_REEL_LAMP_COFS,
		PANM_REEL_LAMP_CNUM,evy,0x7FFF);
#endif
}

/**
 *	@brief	リール停止ランプカラーセットAll
 */
void SlotSub_ReelLampSetAll( SLOTMAIN* wk, LIGHT_STATE st)
{
	int i;
	u16 evy;

	if(st == LIGHT_ON){
		evy = REEL_LAMP_COL_ON;
	}else{
		evy = REEL_LAMP_COL_OFF;
	}
	for(i = 0;i < REEL_MAX;i++){
		sub_ReelLampColorSet( wk, i, evy);
	}
}

/**
 *	@brief	リール停止ランプカラーセット
 */
void SlotSub_ReelLampSet( SLOTMAIN* wk, REEL_NUM no,LIGHT_STATE st)
{
	sub_ReelLampColorSet( wk, no, st);
}

/**
 *	@brief	リール停止ランプ点滅エフェクト　ストップリクエスト
 */
void SlotSub_ReelLampAnimeStopReq( SLOTMAIN* wk, REEL_NUM no)
{
	wk->reel_lamp_anm[no] = TRUE;
}

////////////////////////////////////////////////////////////////////////
/**
 *	@brief	リール停止ランプ点滅エフェクト
 */
////////////////////////////////////////////////////////////////////////
typedef struct _TASKWK_REEL_LAMP{
	u8	reel_no;
	u8	ct;
	u8	dir;
	u8	wait;
	u16	evy;
	SLOTMAIN* psm;
}TASKWK_REEL_LAMP;

static void tcb_ReelLampAnimeTask( TCB_PTR tcb, void* p_work );

/**
 *	@brief	リール停止ランプアニメタスクセット
 */
TCB_PTR AddTCB_ReelLampAnimeSet(SLOTMAIN* wk,REEL_NUM no,int pri)
{
	TASKWK_REEL_LAMP* tp;

	tp = sys_AllocMemory(wk->heapID,sizeof(TASKWK_REEL_LAMP));
	MI_CpuClear8(tp,sizeof(TASKWK_REEL_LAMP));

	tp->evy = REEL_LAMP_COL_ON;
	tp->psm = wk;
	tp->reel_no = no;
	wk->reel_lamp_anm[no] = 0;

	return TCB_Add( tcb_ReelLampAnimeTask, tp, pri);
}

static void tcb_ReelLampAnimeTask( TCB_PTR tcb, void* p_work)
{
	TASKWK_REEL_LAMP* tp = (TASKWK_REEL_LAMP*)p_work;
	SLOTMAIN* wk = tp->psm;

	if(wk->reel_lamp_anm[tp->reel_no]){
		sub_ReelLampColorSet( wk, tp->reel_no, 0);

		wk->reel_lamp_anm[tp->reel_no] = 0;
		sys_FreeMemoryEz(tp);
		TCB_Delete( tcb );
		tcb = NULL;
		return;
	}
	if(tp->wait++ < 8){
		return;
	}
	tp->evy ^= 1;
	tp->wait = 0;
	sub_ReelLampColorSet( wk, tp->reel_no, tp->evy);
}

////////////////////////////////////////////////////////////////////////
/**
 *	@brief	HITライン点滅エフェクトタスク
 */
////////////////////////////////////////////////////////////////////////

typedef struct _TASKWK_HIT_LINE{
	int* tcb_ct;	//タスクの終了を検知するためのカウンタ。TRUEなら再生中。NULL可

	u8	line;
	u8	st;
	u8	wait;
	u8	ct;
	SLOTMAIN* psm;
}TASKWK_HIT_LINE;

static void tcb_HitLineEffTask( TCB_PTR tcb, void* p_work );

/**
 *	@brief	WinLoseアイコン表示エフェクト
 */
TCB_PTR AddTCB_HitLineEff(SLOTMAIN* wk,int line,int* tcb_ct,u8 pri)
{
	TASKWK_HIT_LINE* tp;

	tp = sys_AllocMemory(wk->heapID,sizeof(TASKWK_HIT_LINE));
	MI_CpuClear8(tp,sizeof(TASKWK_HIT_LINE));

	tp->psm = wk;
	tp->line = line;

	sub_BetLineColorSet( wk, tp->line, LIGHT_OFF);

	tp->tcb_ct = tcb_ct;
	if(tp->tcb_ct != NULL){
		(*tp->tcb_ct)++;
	}
	return TCB_Add( tcb_HitLineEffTask, tp, pri);
}

/**
 *	@brief	点滅動作
 */
static void tcb_HitLineEffTask( TCB_PTR tcb, void* p_work )
{
	TASKWK_HIT_LINE* tp = (TASKWK_HIT_LINE*)p_work;
	SLOTMAIN* wk = tp->psm;

	if(tp->wait++ < 8){
		return;
	}
	tp->wait = 0;
	tp->st ^= 1;

	sub_BetLineColorSet( wk, tp->line, tp->st);

	if(tp->ct++ < 6){
		return;
	}
	if(tp->tcb_ct != NULL){
		(*tp->tcb_ct) -= 1;
	}
//	sub_BetLineColorSet( wk, tp->line, 0);

	sys_FreeMemoryEz(p_work);
	TCB_Delete( tcb );
	tcb = NULL;
}

////////////////////////////////////////////////////////////////////////
/**
 *	@brief	上画面ガイド点滅エフェクトタスク
 */
////////////////////////////////////////////////////////////////////////

typedef struct _TASKWK_GUIDE_BLINK{
	int* tcb_ct;	//タスクの終了を検知するためのカウンタ。TRUEなら再生中。NULL可

	u8	game_st;
	u8	code;
	u8	line;
	u8	st;
	u8	wait;
	u8	ct;
	SLOTMAIN* psm;
}TASKWK_GUIDE_BLINK;

static void tcb_GuideBlinkEffTask( TCB_PTR tcb, void* p_work );

/**
 *	@brief	ガイド点滅表示エフェクト
 */
TCB_PTR AddTCB_GuideBlinkEff(SLOTMAIN* wk,GAME_STATE game_st,u8 code ,int* tcb_ct,u8 pri)
{
	TASKWK_GUIDE_BLINK* tp;

	tp = sys_AllocMemory(wk->heapID,sizeof(TASKWK_GUIDE_BLINK));
	MI_CpuClear8(tp,sizeof(TASKWK_GUIDE_BLINK));

	tp->psm = wk;
	tp->code = code;
	tp->game_st = game_st;
	tp->wait = 8;
	tp->tcb_ct = tcb_ct;
	if(tp->tcb_ct != NULL){
		(*tp->tcb_ct)++;
	}
	return TCB_Add( tcb_GuideBlinkEffTask, tp, pri);
}

/**
 *	@brief	点滅動作
 */
static void tcb_GuideBlinkEffTask( TCB_PTR tcb, void* p_work )
{
	TASKWK_GUIDE_BLINK* tp = (TASKWK_GUIDE_BLINK*)p_work;
	SLOTMAIN* wk = tp->psm;

	if(tp->wait++ < 8){
		return;
	}
	if(tp->game_st == STATE_BONUS){	//ボーナスゲーム時
		if(tp->st){
			sub_GuidePokeDraw( wk, tp->code );
		}else{
			sub_GuidePokeDraw( wk, BONUS_BLANK );
		}
	}else{	//ノーマルゲーム時
		if(tp->st){
			SlotSub_GuideBaseDraw( wk, tp->game_st);
			SlotSub_GuideParamDraw( wk ,tp->game_st, BONUS_BLANK );
		}else{
			sub_GuideNormalBlankDraw( wk,tp->code);
		}
	}
	GF_BGL_LoadScreenV_Req(wk->bgl,UFRM_GUIDE);

	tp->wait = 0;
	tp->st ^= 1;
	if(tp->ct++ < 7){
		return;
	}
	if(tp->tcb_ct != NULL){
		(*tp->tcb_ct) -= 1;
	}

	sys_FreeMemoryEz(p_work);
	TCB_Delete( tcb );
	tcb = NULL;
}

////////////////////////////////////////////////////////////////////////
/**
 *	@brief	コイン払い出しエフェクト
 */
////////////////////////////////////////////////////////////////////////

typedef struct _TASKWK_PAYOUT{
	int* tcb_ct;	//タスクの終了を検知するためのカウンタ。TRUEなら再生中。NULL可

	int	payout;
	int	credit;
	int	ct:31;
	int	flag:1;

	SLOTMAIN* psm;
}TASKWK_PAYOUT;

static void tcb_PayoutTask( TCB_PTR tcb, void* p_work );

/**
 *	@brief	コイン払い出し処理タスクセット
 *
 *	@param	credit	現在のコイン枚数
 *	@param	payout	払い出し金額
 *	@param	tcb_ct	タスクの動作数を監視するカウンタへのポインタ(NULL指定可)
 *	@param	pri	タスクの動作プライオリティ
 *
 *	tcb_ctへのポインタは、渡しておくとタスク追加時に +1し、タスクを削除するときに -1します
 *	監視に利用してください
 */
TCB_PTR AddTCB_Payout(SLOTMAIN* wk,int payout,int* tcb_ct,u8 pri)
{
	TASKWK_PAYOUT* tp;

	tp = sys_AllocMemory(wk->heapID,sizeof(TASKWK_PAYOUT));
	MI_CpuClear8(tp,sizeof(TASKWK_PAYOUT));

	tp->credit = wk->credit;
	tp->payout = payout;

	tp->psm = wk;
	tp->tcb_ct = tcb_ct;

	SlotSub_CoinNumDraw(wk,tp->credit,COIN_NUM_CREDIT);
	SlotSub_CoinNumDraw(wk,tp->payout,COIN_NUM_PAYOUT);

	if(wk->credit + payout > COIN_MAX){
		tp->payout = (COIN_MAX-wk->credit);
		wk->credit = COIN_MAX;
	}else{
		wk->credit += payout;
	}

	if(tp->tcb_ct != NULL){
		(*tp->tcb_ct)++;
	}
	return TCB_Add( tcb_PayoutTask, tp, pri);
}

/**
 *	@brief	払い出し処理待ち
 */
static void tcb_PayoutTask( TCB_PTR tcb, void* p_work )
{
	TASKWK_PAYOUT* tp = (TASKWK_PAYOUT*)p_work;
	SLOTMAIN* wk = tp->psm;

	if(tp->payout == 0){
		if(tp->tcb_ct != NULL){
			(*tp->tcb_ct) -= 1;
		}
		if(wk->bonus_game_f){
			sub_GuidePokeDraw( wk, BONUS_BLANK );
			GF_BGL_LoadScreenV_Req(wk->bgl,UFRM_GUIDE);
		}
		sys_FreeMemoryEz(p_work);
		TCB_Delete( tcb );
		tcb = NULL;
		return;
	}
	if(SlotSub_InputCheck( wk )){
		tp->credit += tp->payout;
		if(wk->bonus_game_f){
			wk->bonus_get_ct += tp->payout;
			if(wk->bonus_get_ct > BONUS_GET_CT_MAX){
				wk->bonus_get_ct = BONUS_GET_CT_MAX;
			}
		}
		tp->payout = 0;
	}else{
		tp->credit++;
		if(wk->bonus_game_f){
			if(wk->bonus_get_ct < BONUS_GET_CT_MAX){
				wk->bonus_get_ct++;
			}
		}
		tp->payout--;
	}
	Snd_SePlay(SND_SLOT_PAYOUT);
	SlotSub_CoinNumDraw(wk,tp->credit,COIN_NUM_CREDIT);
	SlotSub_CoinNumDraw(wk,tp->payout,COIN_NUM_PAYOUT);

	if(!wk->bonus_game_f){
		return;
	}
	sub_GuideNumDraw( wk , wk->bonus_get_ct , GUIDE_COIN_KETA, BGS_GET_WX, BGS_GUIDE_WY+BGS_GNUM_SY );

	GF_BGL_LoadScreenV_Req(wk->bgl,UFRM_GUIDE);
}

////////////////////////////////////////////////////////////////////////
/**
 *	@brief	上画面背景スクロールアニメタスク
 */
////////////////////////////////////////////////////////////////////////

typedef struct _TASKWK_BGU_SCRL_ANM{
	int* tcb_ct;	//タスクの終了を検知するためのカウンタ。TRUEなら再生中。NULL可

	u16	seq;
	u8	pal_ct;
	u8	pal_state;
	s16	scrl_ct;
	s16	scrl_y;
	s8	scrl_dy;
	u8	scrl_f;
	BGU_BACK_CODE code;

	SLOTMAIN* psm;
}TASKWK_BGU_SCRL_ANM;

static void tcb_BguScrlAnmTask( TCB_PTR tcb, void* p_work );

static TCB_PTR AddTCB_BguScrlAnm(SLOTMAIN* wk,BGU_BACK_CODE code,u8 pri)
{
	TASKWK_BGU_SCRL_ANM* tp;

	tp = sys_AllocMemory(wk->heapID,sizeof(TASKWK_BGU_SCRL_ANM));
	MI_CpuClear8(tp,sizeof(TASKWK_BGU_SCRL_ANM));

	tp->psm = wk;

	tp->code = code;
	tp->pal_ct = 0;
	tp->pal_state = 0;
	tp->scrl_f = 1;

	if(code == BGU_BACK_HAPPY){
		tp->scrl_dy = 1;
		tp->scrl_y = 256;
	}else if(code == BGU_BACK_SLAMP){
		tp->scrl_dy = -1;
		tp->scrl_y = 0;
	}
	return TCB_Add( tcb_BguScrlAnmTask, tp, pri);
}

/**
 *	@brief	上画面背景パレットアニメ処理
 */
static void tcb_BguScrlAnmTask( TCB_PTR tcb, void* p_work )
{
	TASKWK_BGU_SCRL_ANM* tp = (TASKWK_BGU_SCRL_ANM*)p_work;
	SLOTMAIN* wk = tp->psm;

	if(tp->scrl_dy == 0 || tp->scrl_f == 0){
		return;
	}
	tp->scrl_y += tp->scrl_dy;
	if(tp->scrl_y >= 256){
		tp->scrl_y = 0;
	}else if(tp->scrl_y <= 0){
		tp->scrl_y = 256;
	}
	GF_BGL_ScrollSet( wk->bgl, UFRM_BACK, GF_BGL_SCROLL_Y_SET, tp->scrl_y);
}

////////////////////////////////////////////////////////////////////////
/**
 *	@brief	上画面背景パレットアニメタスク
 */
////////////////////////////////////////////////////////////////////////
typedef struct _TASKWK_BGU_PAL_ANM{
	int* tcb_ct;	//タスクの終了を検知するためのカウンタ。TRUEなら再生中。NULL可

	u16	seq;
	u8	pal_ct;
	u8	pal_state;
	BGU_BACK_CODE code;

	SLOTMAIN* psm;
}TASKWK_BGU_PAL_ANM;

static void tcb_BguPalAnmTask( TCB_PTR tcb, void* p_work );

static TCB_PTR AddTCB_BguPalAnm(SLOTMAIN* wk,BGU_BACK_CODE code,u8 pri)
{
	TASKWK_BGU_PAL_ANM* tp;

	tp = sys_AllocMemory(wk->heapID,sizeof(TASKWK_BGU_PAL_ANM));
	MI_CpuClear8(tp,sizeof(TASKWK_BGU_PAL_ANM));

	tp->psm = wk;

	tp->code = code;
	tp->pal_ct = 0;
	tp->pal_state = 0;
	return TCB_Add( tcb_BguPalAnmTask, tp, pri);
}

/**
 *	@brief	上画面背景パレットアニメ処理
 */
static void tcb_BguPalAnmTask( TCB_PTR tcb, void* p_work )
{
	TASKWK_BGU_PAL_ANM* tp = (TASKWK_BGU_PAL_ANM*)p_work;
	SLOTMAIN* wk = tp->psm;

	if(tp->pal_ct++ >= 15){
		u16 read_pos = (tp->code*2+tp->pal_state)*16;

		tp->pal_ct = 0;
		tp->pal_state ^= 1;

		PaletteWorkSet( wk->palAnm,
			&(wk->pu_back.dat[read_pos]),FADE_MAIN_BG, tp->code*16, 0x20 );
	}
}

/**
 *	@brief	上画面背景スクロールアニメ削除
 */
static void SlotSub_BguScrlAnimeDel( SLOTMAIN* wk, BGU_BACK_CODE code)
{
	BGU_BACK_ANM* anm = &wk->bgu_anm[code];
	TASKWK_BGU_SCRL_ANM* ap;

	if(anm->tcb == NULL){
		MI_CpuClear8(anm,sizeof(BGU_BACK_ANM));
		return;
	}
	ap = (TASKWK_BGU_SCRL_ANM*)TCB_GetWork(anm->tcb);

	GF_BGL_ScrollSet( wk->bgl, UFRM_BACK, GF_BGL_SCROLL_Y_SET, 0);
	sys_FreeMemoryEz(ap);
	TCB_Delete(anm->tcb);

	MI_CpuClear8(anm,sizeof(BGU_BACK_ANM));
}

/**
 *	@brief	上画面背景パレットアニメ削除
 */
static void SlotSub_BguPalAnimeDel( SLOTMAIN* wk, BGU_BACK_CODE code)
{
	BGU_BACK_ANM* anm = &wk->bgu_palanm[code];
	TASKWK_BGU_PAL_ANM* ap;

	if(anm->tcb == NULL){
		MI_CpuClear8(anm,sizeof(BGU_BACK_ANM));
		return;
	}
	ap = (TASKWK_BGU_PAL_ANM*)TCB_GetWork(anm->tcb);

	sys_FreeMemoryEz(ap);
	TCB_Delete(anm->tcb);
	MI_CpuClear8(anm,sizeof(BGU_BACK_ANM));
}

/**
 *	@brief	上画面背景アニメ　削除
 */
void SlotSub_BguBackAnimeDel( SLOTMAIN* wk,BGU_BACK_CODE code)
{
	SlotSub_BguScrlAnimeDel( wk,code );
	SlotSub_BguPalAnimeDel( wk,code );
}

/**
 *	@brief	上画面背景アニメ　セット
 */
static void SlotSub_BguBackPalAnimeAdd( SLOTMAIN* wk, BGU_BACK_CODE code)
{
	wk->bgu_palanm[code].tcb = AddTCB_BguPalAnm(wk,code,TCBPRI_BGU_BACK_ANM);
}
/**
 *	@brief	上画面背景アニメ　セット
 */
static void SlotSub_BguBackScrlAnimeAdd( SLOTMAIN* wk, BGU_BACK_CODE code)
{
	wk->bgu_anm[code].tcb = AddTCB_BguScrlAnm(wk,code,TCBPRI_BGU_BACK_ANM);
}

/**
 *	@brief	上画面背景アニメ　パレットアニメセット
 */
void SlotSub_BguBackAnimeAdd( SLOTMAIN* wk, BGU_BACK_CODE code)
{
	ArcUtil_HDL_ScrnSet( wk->gra_h,
		NARC_slot_gs_gra_efct01_u_nscr+code, wk->bgl, UFRM_BACK, 0, 0, FALSE, wk->heapID);

	SlotSub_BguBackScrlAnimeAdd( wk, code);
	SlotSub_BguBackPalAnimeAdd( wk, code);
	wk->now_bgu_anm = code;
}

////////////////////////////////////////////////////////////////////////
/**
 *	@brief	上画面背景チェンジエフェクトタスク
 */
////////////////////////////////////////////////////////////////////////

typedef struct _TASKWK_BGU_BACK_CHANGE{
	int* tcb_ct;	//タスクの終了を検知するためのカウンタ。TRUEなら再生中。NULL可

	u16	seq;
	u16	evy;
	BGU_BACK_CODE code;

	SLOTMAIN* psm;
}TASKWK_BGU_BACK_CHANGE;

static void tcb_BguBackChangeTask( TCB_PTR tcb, void* p_work );

TCB_PTR AddTCB_BguBackChange(SLOTMAIN* wk,BGU_BACK_CODE code,int* tcb_ct)
{
	TASKWK_BGU_BACK_CHANGE* tp;

	tp = sys_AllocMemory(wk->heapID,sizeof(TASKWK_BGU_BACK_CHANGE));
	MI_CpuClear8(tp,sizeof(TASKWK_BGU_BACK_CHANGE));

	tp->evy = 0;
	tp->code = code;

	tp->psm = wk;
	tp->tcb_ct = tcb_ct;

	if(tp->tcb_ct != NULL){
		(*tp->tcb_ct)++;
	}
	return TCB_Add( tcb_BguBackChangeTask, tp, TCBPRI_BGU_BACK_ANM_CHG);
}

/**
 *	@brief	上画面背景切替処理
 */
static void tcb_BguBackChangeTask( TCB_PTR tcb, void* p_work )
{
	TASKWK_BGU_BACK_CHANGE* tp = (TASKWK_BGU_BACK_CHANGE*)p_work;
	SLOTMAIN* wk = tp->psm;

	switch(tp->seq){
	case 0:
		BrightnessChgInit();
		ChangeBrightnessRequest(8, BRIGHTNESS_WHITE, BRIGHTNESS_NORMAL,
			PLANEMASK_BG3, MASK_MAIN_DISPLAY);
		tp->seq++;
		break;
	case 1:
		BrightnessChgMain();
		if(!IsFinishedBrightnessChg(MASK_MAIN_DISPLAY)){
			return;
		}

		SlotSub_BguBackAnimeDel( wk, wk->now_bgu_anm );
		SlotSub_BguBackAnimeAdd( wk, tp->code );

		BrightnessChgInit();
		ChangeBrightnessRequest(8, BRIGHTNESS_NORMAL, BRIGHTNESS_WHITE,
			PLANEMASK_BG3, MASK_MAIN_DISPLAY);
		tp->seq++;
		break;
	case 2:
		BrightnessChgMain();
		if(!IsFinishedBrightnessChg(MASK_MAIN_DISPLAY)){
			return;
		}
		BrightnessChgInit();
		tp->seq++;
		break;
	default:
		if(tp->tcb_ct != NULL){
			(*tp->tcb_ct) -= 1;
		}
		sys_FreeMemoryEz(p_work);
		TCB_Delete( tcb );
		tcb = NULL;
		return;
	}
}

////////////////////////////////////////////////////////////////////////
/**
 *	@brief	上画面モードチェンジ背景エフェクトタスク　スクロールしながら切替
 */
////////////////////////////////////////////////////////////////////////

typedef struct _TASKWK_BGU_MCHG_EFF{
	int* tcb_ct;	//タスクの終了を検知するためのカウンタ。TRUEなら再生中。NULL可

	u8	code1;

	u16	scr_ct;
	s16	line;
	u16	seq;
	u16	evy;
	BGU_BACK_CODE code;

	SLOTMAIN* psm;
}TASKWK_BGU_MCHG_EFF;

static void tcb_BguMChgEff( TCB_PTR tcb, void* p_work );
static void sub_BguMChgEffLineDraw(SLOTMAIN* wk,u8 code,u16 line);

static TCB_PTR AddTCB_BguMChgEff(SLOTMAIN* wk,BGU_BACK_CODE code1,BGU_BACK_CODE code2,int* tcb_ct)
{
	int i;
	TASKWK_BGU_MCHG_EFF* tp;

	tp = sys_AllocMemory(wk->heapID,sizeof(TASKWK_BGU_MCHG_EFF));
	MI_CpuClear8(tp,sizeof(TASKWK_BGU_MCHG_EFF));

	tp->evy = 0;
	tp->code1 = code1;
	tp->code = code2;

	tp->psm = wk;
	tp->tcb_ct = tcb_ct;

	tp->line = 31;

	tp->scr_ct += 0;
	GF_BGL_ScrollSet( wk->bgl, UFRM_BACK, GF_BGL_SCROLL_Y_SET, tp->scr_ct);

	sub_BguMChgEffLineDraw(wk,tp->code,tp->line--);
	sub_BguMChgEffLineDraw(wk,tp->code,tp->line);
	if(tp->tcb_ct != NULL){
		(*tp->tcb_ct)++;
	}
	return TCB_Add( tcb_BguMChgEff, tp, TCBPRI_BGU_EFFECT);
}

/*
 *	@brief	キャラクタ単位のラインを書き込む
 */
static void sub_BguMChgEffLineDraw(SLOTMAIN* wk,u8 code,u16 line)
{
	SLOT_SCR* ps = &wk->su_anm[code];

	GF_BGL_ScrWriteExpand(wk->bgl,UFRM_BACK,
		0,line,32,1,
		ps->dat,0,line,
		ps->siz_x,ps->siz_y);
	GF_BGL_LoadScreenV_Req(wk->bgl,UFRM_BACK);
}

/**
 *	@brief	上画面背景切替処理
 */
static void tcb_BguMChgEff( TCB_PTR tcb, void* p_work )
{
	TASKWK_BGU_MCHG_EFF* tp = (TASKWK_BGU_MCHG_EFF*)p_work;
	SLOTMAIN* wk = tp->psm;

	GF_BGL_ScrollSet( wk->bgl, UFRM_BACK, GF_BGL_SCROLL_Y_DEC, 16);

	tp->scr_ct += 16;
	tp->line = (tp->line+31)%32;
	sub_BguMChgEffLineDraw(wk,tp->code,tp->line);
	tp->line = (tp->line+31)%32;
	sub_BguMChgEffLineDraw(wk,tp->code,tp->line);
	if(tp->scr_ct < (256-16)){
		return;
	}
//	GF_BGL_ScrollSet( wk->bgl, UFRM_BACK, GF_BGL_SCROLL_Y_SET, 0);
	if(tp->tcb_ct != NULL){
		(*tp->tcb_ct) -= 1;
	}
	sys_FreeMemoryEz(p_work);
	TCB_Delete( tcb );
	tcb = NULL;
	return;
}

////////////////////////////////////////////////////////////////////////
/**
 *	@brief	上画面モードチェンジ背景エフェクトタスク
 */
////////////////////////////////////////////////////////////////////////

typedef struct _TASKWK_BGU_MODE_CHANGE{
	int* tcb_ct;	//タスクの終了を検知するためのカウンタ。TRUEなら再生中。NULL可

	int	eff_tcb_ct;
	u8	roll_ct;
	u8	roll_ct_max;
	u8	now_mode;
	u8	next_mode;
	u8	code1;
	u8	code2;

	u16	seq;
	u16	evy;
	BGU_BACK_CODE code;

	CLACT_WORK_PTR act;
	SLOTMAIN* psm;
}TASKWK_BGU_MODE_CHANGE;

static void tcb_BguModeChangeTask( TCB_PTR tcb, void* p_work );

/**
 *	@brief	上画面モードチェンジエフェクト
 */
TCB_PTR AddTCB_BguModeChange(SLOTMAIN* wk,BGU_BACK_CODE now_mode,BGU_BACK_CODE next_mode,int* tcb_ct)
{
	int i;
	TASKWK_BGU_MODE_CHANGE* tp;

	tp = sys_AllocMemory(wk->heapID,sizeof(TASKWK_BGU_MODE_CHANGE));
	MI_CpuClear8(tp,sizeof(TASKWK_BGU_MODE_CHANGE));

	tp->evy = 0;
	tp->now_mode = now_mode;
	tp->next_mode = next_mode;

	tp->code1 = tp->now_mode;
	tp->code2 = (tp->code1+1)%SLOT_MCHG_ANM_NUM;

	tp->roll_ct_max = SLOT_MCHG_ANM_NUM*(2+(gf_rand()%5));
	if(tp->next_mode-tp->now_mode < 0){
		tp->roll_ct_max += (tp->next_mode-tp->now_mode)+SLOT_MCHG_ANM_NUM;
	}else{
		tp->roll_ct_max += (tp->next_mode-tp->now_mode);
	}
	tp->psm = wk;
	tp->tcb_ct = tcb_ct;

	tp->act = wk->pAct[ACT_ICON01];
	for(i = 0;i < SLOT_MCHG_ANM_NUM;i++){
		if(i!=tp->code1){
			SlotSub_BguBackPalAnimeAdd( wk, i );
		}
	}

	OS_Printf("SlotModeChange now = %d,next = %d, roll_ct = %d\n",now_mode,next_mode,tp->roll_ct_max);
	if(tp->tcb_ct != NULL){
		(*tp->tcb_ct)++;
	}
	return TCB_Add( tcb_BguModeChangeTask, tp, TCBPRI_BGU_BACK_ANM_CHG);
}

/**
 *	@brief	上画面背景切替処理
 */
static void tcb_BguModeChangeTask( TCB_PTR tcb, void* p_work )
{
	TASKWK_BGU_MODE_CHANGE* tp = (TASKWK_BGU_MODE_CHANGE*)p_work;
	SLOTMAIN* wk = tp->psm;

	switch(tp->seq){
	case 0:
		BrightnessChgInit();
		ChangeBrightnessRequest(16, BRIGHTNESS_WHITE, BRIGHTNESS_NORMAL,
			PLANEMASK_BG3, MASK_MAIN_DISPLAY);
		tp->seq++;
		break;
	case 1:
		BrightnessChgMain();
		if(!IsFinishedBrightnessChg(MASK_MAIN_DISPLAY)){
			return;
		}
		CLACT_AnmChg( tp->act, ANMU_ICON_IRA2 );
		CLACT_DrawPriorityChg( tp->act, ACTU_SPRI_IRA2 );
		CATS_ObjectPosSet(tp->act,ICON_CX+16,ICON_CY);
		CLACT_SetDrawFlag(tp->act, TRUE );

		SlotSub_BguScrlAnimeDel( wk, tp->now_mode);
		BrightnessChgInit();
		ChangeBrightnessRequest(16, BRIGHTNESS_NORMAL, BRIGHTNESS_WHITE,
			PLANEMASK_BG3, MASK_MAIN_DISPLAY);
		tp->seq++;
		break;
	case 2:
		BrightnessChgMain();
		if(!IsFinishedBrightnessChg(MASK_MAIN_DISPLAY)){
			return;
		}
		tp->seq++;
		//ここはスルー
	case 3:
		AddTCB_BguMChgEff(wk,tp->code1,tp->code2,&tp->eff_tcb_ct);
		tp->seq++;
		break;
	case 4:
		if(tp->eff_tcb_ct){
			return;
		}
		tp->code1 = tp->code2;
		tp->code2 = (tp->code2+1)%SLOT_MCHG_ANM_NUM;
		if(++tp->roll_ct < tp->roll_ct_max){
			tp->seq = 3;
			break;
		}
		BrightnessChgInit();
		ChangeBrightnessRequest(8, BRIGHTNESS_WHITE, BRIGHTNESS_NORMAL,
			PLANEMASK_BG3, MASK_MAIN_DISPLAY);
		OS_Printf("SlotModeChangeEnd now = %d\n",tp->code1);
		tp->seq++;
		break;
	case 5:
		BrightnessChgMain();
		if(!IsFinishedBrightnessChg(MASK_MAIN_DISPLAY)){
			return;
		}
		CLACT_SetDrawFlag(tp->act, FALSE );
		CLACT_DrawPriorityChg( tp->act, ACTU_SPRI_ICON );
		SlotSub_BguBackScrlAnimeAdd( wk, tp->code1 );
		wk->now_bgu_anm = tp->code1;

		BrightnessChgInit();
		ChangeBrightnessRequest(16, BRIGHTNESS_NORMAL, BRIGHTNESS_WHITE,
			PLANEMASK_BG3, MASK_MAIN_DISPLAY);
		tp->seq++;
		break;
	default:
		BrightnessChgMain();
		if(!IsFinishedBrightnessChg(MASK_MAIN_DISPLAY)){
			return;
		}
		{
			int i;
			for(i = 0;i < SLOT_MCHG_ANM_NUM;i++){
				if(i!=tp->code1){
					SlotSub_BguPalAnimeDel( wk, i );
				}
			}
		}
		if(tp->tcb_ct != NULL){
			(*tp->tcb_ct) -= 1;
		}
		sys_FreeMemoryEz(p_work);
		TCB_Delete( tcb );
		tcb = NULL;
		return;
	}
}

/**
 *	@brief	下書き絵BG書き込み
 */
void SlotSub_PictDraw( SLOTMAIN* wk, PICT_CODE pict, BOOL draft_f)
{
	int frame = UFRM_PICT+draft_f;

	GF_BGL_ScrWriteExpand(wk->bgl,frame,
		BGS_PICT_WX,BGS_PICT_WY,BGS_PICT_SX,BGS_PICT_SY,
		wk->su_pict.dat,draft_f*BGS_PICT_SX,pict*BGS_PICT_SY,
		wk->su_pict.siz_x,wk->su_pict.siz_y);

	GF_BGL_LoadScreenV_Req(wk->bgl,frame);
}

////////////////////////////////////////////////////////////////////////
/**
 *	@brief	下書き絵描画タスク
 */
////////////////////////////////////////////////////////////////////////

typedef struct _TASKWK_DRAFT_DRAW{
	int* tcb_ct;	//タスクの終了を検知するためのカウンタ。TRUEなら再生中。NULL可

	u16	seq;
	u8	evy;
	u8	pict;
	SLOTMAIN* psm;
}TASKWK_DRAFT_DRAW;

static void tcb_DraftDrawTask( TCB_PTR tcb, void* p_work );

TCB_PTR AddTCB_DraftDraw(SLOTMAIN* wk,PICT_CODE pict,int* tcb_ct,u8 pri)
{
	TASKWK_DRAFT_DRAW* tp;

	tp = sys_AllocMemory(wk->heapID,sizeof(TASKWK_DRAFT_DRAW));
	MI_CpuClear8(tp,sizeof(TASKWK_DRAFT_DRAW));

	tp->psm = wk;
	tp->pict = pict;
	SoftFadePfd(wk->palAnm,FADE_MAIN_BG,
		(PANM_DRAFT_IDX*16),PANM_DRAFT_CNUM,16,PANM_DRAFT_COL);
	SlotSub_PictDraw( wk, tp->pict, TRUE);

	tp->evy = 16;
	tp->tcb_ct = tcb_ct;
	if(tp->tcb_ct != NULL){
		(*tp->tcb_ct)++;
	}
	return TCB_Add( tcb_DraftDrawTask, tp, pri);
}

/**
 *	@brief	ピクチャー下書き処理
 */
static void tcb_DraftDrawTask( TCB_PTR tcb, void* p_work )
{
	TASKWK_DRAFT_DRAW* tp = (TASKWK_DRAFT_DRAW*)p_work;
	SLOTMAIN* wk = tp->psm;

	SoftFadePfd(wk->palAnm,FADE_MAIN_BG,
		(PANM_DRAFT_IDX*16),PANM_DRAFT_CNUM,tp->evy,PANM_DRAFT_COL);
	if(tp->evy-- > 0){
		return;
	}

	if(tp->tcb_ct != NULL){
		(*tp->tcb_ct) -= 1;
	}
	sys_FreeMemoryEz(p_work);
	TCB_Delete( tcb );
	tcb = NULL;
}

////////////////////////////////////////////////////////////////////////
/**
 *	@brief	当たり絵描画タスク
 */
////////////////////////////////////////////////////////////////////////

typedef struct _TASKWK_PICT_DRAW{
	int* tcb_ct;	//タスクの終了を検知するためのカウンタ。TRUEなら再生中。NULL可

	u16	seq;
	u8	pict;
	u8	sx;
	u8	sy;
	u8	spd;
	SLOTMAIN* psm;
}TASKWK_PICT_DRAW;

static void tcb_PictDrawTask( TCB_PTR tcb, void* p_work );

TCB_PTR AddTCB_PictDraw(SLOTMAIN* wk,PICT_CODE pict,int* tcb_ct,u8 pri)
{
	TASKWK_PICT_DRAW* tp;

	tp = sys_AllocMemory(wk->heapID,sizeof(TASKWK_PICT_DRAW));
	MI_CpuClear8(tp,sizeof(TASKWK_PICT_DRAW));

	tp->psm = wk;
	tp->pict = pict;

	tp->sx = 0;
	tp->sy = BGWIN_PICT_H;
	tp->spd = 2;
	G2_SetWnd0Position( BGWIN_PICT_X, BGWIN_PICT_Y,
		BGWIN_PICT_X+BGWIN_PICT_W, BGWIN_PICT_Y+tp->sy );
//	G2_SetWnd1Position( BGWIN_PICT_X, BGWIN_PICT_Y, tp->sx, tp->sy+1 );

//	GX_SetVisibleWnd(GX_WNDMASK_W0|GX_WNDMASK_W1);
	GX_SetVisibleWnd(GX_WNDMASK_W0);

	SlotSub_PictDraw( wk, tp->pict, FALSE);
	SlotSub_DooburuAnmSet( wk, DOOBURU_DRAW );

	Snd_SePlay(SND_SLOT_SKETCH);

	tp->tcb_ct = tcb_ct;
	if(tp->tcb_ct != NULL){
		(*tp->tcb_ct)++;
	}
	return TCB_Add( tcb_PictDrawTask, tp, pri);
}

/**
 *	@brief	当たり絵描画処理
 */
static void tcb_PictDrawTask( TCB_PTR tcb, void* p_work )
{
	TASKWK_PICT_DRAW* tp = (TASKWK_PICT_DRAW*)p_work;
	SLOTMAIN* wk = tp->psm;

	G2_SetWnd0Position( BGWIN_PICT_X, BGWIN_PICT_Y,
		BGWIN_PICT_X+BGWIN_PICT_W, BGWIN_PICT_Y+tp->sy );

	if(tp->sy > 0){
		tp->sy -= tp->spd;
		return;
	}
	GX_SetVisibleWnd(GX_WNDMASK_NONE);

	if(tp->tcb_ct != NULL){
		(*tp->tcb_ct) -= 1;
	}
	SlotSub_DooburuAnmSet( wk, DOOBURU_BACK );
	sys_FreeMemoryEz(p_work);
	TCB_Delete( tcb );
	tcb = NULL;
}

////////////////////////////////////////////////////////////////////////
/**
 *	@brief	絵消去エフェクトタスク
 */
////////////////////////////////////////////////////////////////////////

typedef struct _TASKWK_PICT_OFF{
	int* tcb_ct;	//タスクの終了を検知するためのカウンタ。TRUEなら再生中。NULL可

	u16	seq;
	u8	evy;
	SLOTMAIN* psm;
}TASKWK_PICT_OFF;

static void tcb_PictOffTask( TCB_PTR tcb, void* p_work );

TCB_PTR AddTCB_PictOff(SLOTMAIN* wk,int* tcb_ct,u8 pri)
{
	TASKWK_PICT_OFF* tp;

	tp = sys_AllocMemory(wk->heapID,sizeof(TASKWK_PICT_OFF));
	MI_CpuClear8(tp,sizeof(TASKWK_PICT_OFF));

	tp->psm = wk;
	tp->evy = 0;

	tp->tcb_ct = tcb_ct;
	if(tp->tcb_ct != NULL){
		(*tp->tcb_ct)++;
	}
	return TCB_Add( tcb_PictOffTask, tp, pri);
}

/**
 *	@brief	ピクチャー消去
 */
static void tcb_PictOffTask( TCB_PTR tcb, void* p_work )
{
	TASKWK_PICT_OFF* tp = (TASKWK_PICT_OFF*)p_work;
	SLOTMAIN* wk = tp->psm;

	SoftFadePfd(wk->palAnm,FADE_MAIN_BG,
		(PANM_DRAFT_IDX*16),PANM_DRAFT_CNUM*2,tp->evy,PANM_DRAFT_COL);
	tp->evy += 2;
	if(tp->evy < 16){
		return;
	}
	//背景クリア
	SlotSub_PictDraw( wk, PICT_BLANK, FALSE);
	SlotSub_PictDraw( wk, PICT_BLANK, TRUE);

	//パレットを元に戻す
	SoftFadePfd(wk->palAnm,FADE_MAIN_BG,
		(PANM_PICT_IDX*16),PANM_PICT_CNUM,0,PANM_DRAFT_COL);

	if(tp->tcb_ct != NULL){
		(*tp->tcb_ct) -= 1;
	}
	sys_FreeMemoryEz(p_work);
	TCB_Delete( tcb );
	tcb = NULL;
}

////////////////////////////////////////////////////////////////////////
/**
 *	@brief	アイコンエフェクト全削除
 */
////////////////////////////////////////////////////////////////////////
void SlotSub_IconEffVanishAll( SLOTMAIN* wk )
{
	int i;

	for(i = 0;i < ACT_ICONMAX;i++){
		CLACT_SetDrawFlag(wk->pAct[ACT_ICON01+i], FALSE );
	}
}

////////////////////////////////////////////////////////////////////////
/**
 *	@brief	ビックリアイコンエフェクトタスク
 */
////////////////////////////////////////////////////////////////////////

typedef struct _TASKWK_EX_ICON{
	int* tcb_ct;	//タスクの終了を検知するためのカウンタ。TRUEなら再生中。NULL可

	u16	seq;
	u8	dy;
	u8	mode;

	CLACT_WORK_PTR act;

	SLOTMAIN* psm;
}TASKWK_EX_ICON;

static void tcb_ExIconTask( TCB_PTR tcb, void* p_work );

/**
 *	@brief	ビックリマークアイコン表示エフェクト
 */
TCB_PTR AddTCB_ExIconEff(SLOTMAIN* wk,int mode,int* tcb_ct,u8 pri)
{
	TASKWK_EX_ICON* tp;

	tp = sys_AllocMemory(wk->heapID,sizeof(TASKWK_EX_ICON));
	MI_CpuClear8(tp,sizeof(TASKWK_EX_ICON));

	tp->psm = wk;
	tp->dy = 0;
	tp->mode = mode;

	tp->act = wk->pAct[ACT_ICON01];
	CLACT_AnmChg( tp->act, ANMU_ICON_EX1 + mode );
	CATS_ObjectPosSet(tp->act,ICON_CX,ICON_CY);

	CLACT_SetDrawFlag(tp->act, TRUE );
	Snd_SePlay(SND_SLOT_EX_ICON);

	tp->tcb_ct = tcb_ct;
	if(tp->tcb_ct != NULL){
		(*tp->tcb_ct)++;
	}
	return TCB_Add( tcb_ExIconTask, tp, pri);
}

/**
 *	@brief	アイコン動作
 */
static void tcb_ExIconTask( TCB_PTR tcb, void* p_work )
{
	TASKWK_EX_ICON* tp = (TASKWK_EX_ICON*)p_work;
	SLOTMAIN* wk = tp->psm;

	CATS_ObjectPosSet(tp->act,ICON_CX,ICON_CY-tp->dy);
	tp->dy += 2;
	if(tp->dy < 16){
		return;
	}
//	CLACT_SetDrawFlag(tp->act, FALSE );

	if(tp->tcb_ct != NULL){
		(*tp->tcb_ct) -= 1;
	}
	sys_FreeMemoryEz(p_work);
	TCB_Delete( tcb );
	tcb = NULL;
}

////////////////////////////////////////////////////////////////////////
/**
 *	@brief	WinLoseアイコンエフェクトタスク
 */
////////////////////////////////////////////////////////////////////////

typedef struct _TASKWK_WL_ICON{
	int* tcb_ct;	//タスクの終了を検知するためのカウンタ。TRUEなら再生中。NULL可

	u8	seq;
	u8	wait;
	u8	mode;
	u8	num;
	u8	r;

	s16	x,y;
	s16	sy;
	s16	dy;

	fx32	dx,sx;

	CLACT_WORK_PTR act;

	SLOTMAIN* psm;
}TASKWK_WL_ICON;

static void tcb_WinLoseIconTask( TCB_PTR tcb, void* p_work );

/**
 *	@brief	WinLoseアイコン表示エフェクト
 */
static TCB_PTR AddTCB_WinLoseIconEff(SLOTMAIN* wk,int mode,int no,s16 x,s16 y,int* tcb_ct,u8 pri)
{
	TASKWK_WL_ICON* tp;

	tp = sys_AllocMemory(wk->heapID,sizeof(TASKWK_WL_ICON));
	MI_CpuClear8(tp,sizeof(TASKWK_WL_ICON));

	tp->psm = wk;
	tp->x = x;
	tp->y = y;
	tp->mode = mode;

	tp->sx = FX32_CONST(6+gf_rand()%4);
	tp->sy = 32;

	tp->dx = FX32_CONST(tp->x);
	tp->r = ((SlotSub_Rand(4)*8)+336)%360;

	tp->act = wk->pAct[ACT_ICON01+no];
	CLACT_AnmChg( tp->act, ANMU_ICON_MOYA + mode );
	CATS_ObjectPosSet(tp->act,x,y);

	CLACT_SetDrawFlag(tp->act, TRUE );
	Snd_SePlay(SND_SLOT_WINLOSE_ICON);

	tp->tcb_ct = tcb_ct;
	if(tp->tcb_ct != NULL){
		(*tp->tcb_ct)++;
	}
	return TCB_Add( tcb_WinLoseIconTask, tp, pri);
}

/**
 *	@brief	アイコン動作
 */
static void tcb_WinLoseIconTask( TCB_PTR tcb, void* p_work )
{
	TASKWK_WL_ICON* tp = (TASKWK_WL_ICON*)p_work;
	SLOTMAIN* wk = tp->psm;
	fx32	dx;

	switch(tp->seq){
	case 0:
		dx = FX_Mul(Sin360(tp->r),tp->sx);

		CATS_ObjectPosSet(tp->act,tp->x+FX_Whole(dx),tp->y-tp->dy);

		tp->r += 8;
		if(tp->r >= 360){
			tp->r = 0;
		}
		tp->dy += 1;

		if(tp->dy > (tp->sy-6)){
			CLACT_SetDrawFlag(tp->act,tp->dy%2);
		}
		if(tp->dy < tp->sy){
			return;
		}
		tp->wait = 15;
		tp->seq++;
		break;
	case 1:
	default:
		if(tp->wait-- > 0){
			return;
		}
		CLACT_SetDrawFlag(tp->act, FALSE );

		if(tp->tcb_ct != NULL){
			(*tp->tcb_ct) -= 1;
		}
		sys_FreeMemoryEz(p_work);
		TCB_Delete( tcb );
		tcb = NULL;
	}
}

/**
 *	@brief	WinLoseアイコン登録
 */
void SlotSub_WinLoseIconSet( SLOTMAIN* wk, int num, int mode )
{
	switch(num){
	case 1:
		AddTCB_WinLoseIconEff( wk,mode,0,ICON_CX,ICON_CY,&wk->eff_tcb_ct,TCBPRI_MONITER_EFF);
		break;
	case 2:
		AddTCB_WinLoseIconEff( wk,mode,0,ICON_CX-12,ICON_CY+gf_rand()%16,&wk->eff_tcb_ct,TCBPRI_MONITER_EFF);
		AddTCB_WinLoseIconEff( wk,mode,1,ICON_CX+12,ICON_CY+gf_rand()%16,&wk->eff_tcb_ct,TCBPRI_MONITER_EFF);
		break;
	case 3:
#if 0
		AddTCB_WinLoseIconEff( wk,mode,0,ICON_CX,ICON_CY+gf_rand()%8,&wk->eff_tcb_ct,TCBPRI_MONITER_EFF);
		AddTCB_WinLoseIconEff( wk,mode,1,ICON_CX+16,ICON_CY+gf_rand()%8+16,&wk->eff_tcb_ct,TCBPRI_MONITER_EFF);
		AddTCB_WinLoseIconEff( wk,mode,2,ICON_CX-16,ICON_CY+gf_rand()%8+8,&wk->eff_tcb_ct,TCBPRI_MONITER_EFF);
#else
		AddTCB_WinLoseIconEff( wk,mode,0,ICON_CX,ICON_CY+gf_rand()%16,&wk->eff_tcb_ct,TCBPRI_MONITER_EFF);
		AddTCB_WinLoseIconEff( wk,mode,1,ICON_CX+16,ICON_CY+gf_rand()%16,&wk->eff_tcb_ct,TCBPRI_MONITER_EFF);
		AddTCB_WinLoseIconEff( wk,mode,2,ICON_CX-16,ICON_CY+gf_rand()%16,&wk->eff_tcb_ct,TCBPRI_MONITER_EFF);
#endif
		break;
	}
}

////////////////////////////////////////////////////////////////////////
/**
 *	@brief	Emotionアイコンエフェクトタスク
 */
////////////////////////////////////////////////////////////////////////

typedef struct _TASKWK_EM_ICON{
	int* tcb_ct;	//タスクの終了を検知するためのカウンタ。TRUEなら再生中。NULL可

	u16	seq;
	u8	mode;
	u8	num;
	u8	ct;

	s16	sx,sy;
	s16	ex,ey;

	fx32	dx,dy;

	VecFx32	vec;
	CLACT_WORK_PTR act;

	SLOTMAIN* psm;
}TASKWK_EM_ICON;

static void tcb_EmotionIconTask( TCB_PTR tcb, void* p_work );

/**
 *	@brief	Emotionアイコン表示エフェクト
 */
static TCB_PTR AddTCB_EmotionIconEff(SLOTMAIN* wk,int mode,int no,s16 x,s16 y,u8 pri,int* tcb_ct)
{
	TASKWK_EM_ICON* tp;

	tp = sys_AllocMemory(wk->heapID,sizeof(TASKWK_EM_ICON));
	MI_CpuClear8(tp,sizeof(TASKWK_EM_ICON));

	tp->psm = wk;
	tp->sx = ICON_CX;
	tp->sy = ICON_CY;
	tp->ex = x;
	tp->ey = y;
	tp->mode = mode;

	tp->dx = FX_Div(FX32_CONST(tp->ex-tp->sx),FX32_CONST(EM_ICON_EFF_TIME));
	tp->dy = FX_Div(FX32_CONST(tp->ey-tp->sy),FX32_CONST(EM_ICON_EFF_TIME));

	IWASAWA_PRINT("vec %d = %d,%d\n",no,tp->ex,tp->ey);
	tp->ct = EM_ICON_EFF_TIME;

	tp->act = wk->pAct[ACT_ICON01+no];
	CLACT_AnmChg( tp->act, ANMU_ICON_NIKO + mode );
	CLACT_DrawPriorityChg( tp->act, pri);

	tp->vec.x = FX32_CONST(tp->sx);
	tp->vec.y = FX32_CONST(tp->sy);
	tp->vec.z = 0;
	CLACT_SetMatrix(tp->act, &tp->vec);

	CLACT_SetDrawFlag(tp->act, TRUE );

	tp->tcb_ct = tcb_ct;
	if(tp->tcb_ct != NULL){
		(*tp->tcb_ct)++;
	}
	return TCB_Add( tcb_EmotionIconTask, tp, TCBPRI_MONITER_EFF);
}

/**
 *	@brief	アイコン動作
 */
static void tcb_EmotionIconTask( TCB_PTR tcb, void* p_work )
{
	TASKWK_EM_ICON* tp = (TASKWK_EM_ICON*)p_work;
	SLOTMAIN* wk = tp->psm;
	fx32	dx;

	switch(tp->seq){
	case 0:
		tp->vec.x += tp->dx;
		tp->vec.y += tp->dy;
		CLACT_SetMatrix(tp->act, &tp->vec);

		if(--tp->ct > 0 ){
			return;
		}
		CATS_ObjectPosSet(tp->act,tp->ex,tp->ey);

		tp->ct = 15;
		tp->seq++;
		return;
	case 1:
		if(--tp->ct > 0){
			return;
		}
		tp->seq++;
		return;
	case 2:
		break;
	}
	CLACT_SetDrawFlag(tp->act, FALSE );

	if(tp->tcb_ct != NULL){
		(*tp->tcb_ct) -= 1;
	}
	sys_FreeMemoryEz(p_work);
	TCB_Delete( tcb );
	tcb = NULL;
}

static const u8 EmIconPos[15][3] = {
 //1
 {ICON_CX+EM_ICON_OX1,EM_ICON_Y1,ACTU_SPRI_ICON+0},	//0
 //2
 {ICON_CX-EM_ICON_OX2,EM_ICON_Y1,ACTU_SPRI_ICON+0},	//1
 {ICON_CX+EM_ICON_OX2,EM_ICON_Y1,ACTU_SPRI_ICON+0},	//2
 //3
 {ICON_CX+EM_ICON_OX1,EM_ICON_Y1-6,ACTU_SPRI_ICON+0},	//3
 {ICON_CX-EM_ICON_OX3,EM_ICON_Y1,ACTU_SPRI_ICON+1},	//4
 {ICON_CX+EM_ICON_OX3,EM_ICON_Y1,ACTU_SPRI_ICON+1},	//5
 //4
 {ICON_CX-EM_ICON_OX2,EM_ICON_Y1,ACTU_SPRI_ICON+0},	//6
 {ICON_CX+EM_ICON_OX2,EM_ICON_Y1,ACTU_SPRI_ICON+0},	//7
 {ICON_CX-EM_ICON_OX3,EM_ICON_Y2,ACTU_SPRI_ICON+1},	//8
 {ICON_CX+EM_ICON_OX3,EM_ICON_Y2,ACTU_SPRI_ICON+1},	//9
 //5
 {ICON_CX-EM_ICON_OX2,EM_ICON_Y1,ACTU_SPRI_ICON+0},	//10
 {ICON_CX+EM_ICON_OX2,EM_ICON_Y1,ACTU_SPRI_ICON+0},	//11
 {ICON_CX+EM_ICON_OX1,EM_ICON_Y2,ACTU_SPRI_ICON+1},	//12
 {ICON_CX-EM_ICON_OX3,EM_ICON_Y2,ACTU_SPRI_ICON+2},	//13
 {ICON_CX+EM_ICON_OX3,EM_ICON_Y2,ACTU_SPRI_ICON+2},	//14
};

/**
 *	@brief	Emotionアイコン登録
 */
void SlotSub_EmotionIconSet( SLOTMAIN* wk )
{
	int mode,num,abs,i;

	static const pidx[] = {0,1,3,6,10};

//	wk->stress_ct = 15;
	if(wk->stress_ct == 0){
		return;
	}
	if(wk->stress_ct < 0){
		mode = 0;
		abs = wk->stress_ct*-1;
	}else{
		mode = 1;
		abs = wk->stress_ct;
	}
	num = ((abs-1) / 3) + 1;
	if(num > 5){
		num = 5;
	}
	for(i = 0;i < num;i++){
		u8	idx = pidx[num-1]+i;

		AddTCB_EmotionIconEff( wk, mode, i,
			EmIconPos[idx][0],
			EmIconPos[idx][1],
			EmIconPos[idx][2],
			&wk->eff_tcb_ct);
	}
	Snd_SePlay(SND_SLOT_EMOTION_ICON);
}

/**
 *	@brief	数字の桁取得
 */
static int get_num_keta(u32 num,u8 keta)
{
	const u32 tbl[] = {
	 1,10,100,1000,10000,100000,1000000,10000000
	};
	return (num%tbl[keta+1])/tbl[keta];
}

///////////////////////////////////////////////////////////////////////////
//デバッグ
#ifdef PM_DEBUG
static void debug_WinLinePut(SLOTMAIN* wk,u8 px,u8 py,u8 sy,u8 msg_idx);

void Debug_WinVisibleCheck(SLOTMAIN* wk)
{
	if((sys.trg & PAD_BUTTON_SELECT)){
		wk->deb_print_f ^= 1;
		if(wk->deb_print_f){
			wk->deb_lot_basic = 0;
			wk->deb_lot_ex = 0;
			Debug_WinUpdate(wk);
		}else{
			wk->deb_lot_basic = 0;
			wk->deb_lot_ex = 0;
			wk->deb_auto_f = FALSE;
			wk->deb_auto_ct = 0;
			GF_BGL_BmpWinOff(&wk->deb_win);
		}
		return;
	}
	if(!wk->deb_print_f){
		return;
	}
	if(sys.trg & PAD_BUTTON_X){
		if(wk->bonus_game_f){
			wk->deb_lot_basic = (wk->deb_lot_basic+1)%(BONUS_CODE_MAX+1);
		}else{
			wk->deb_lot_basic = (wk->deb_lot_basic+1)%(PRIZE_CODE_MAX+1);
		}
		Snd_SePlay(SEQ_SE_DP_SELECT);
		if((wk->deb_lot_basic > 4 && wk->deb_lot_ex > 2)){
			wk->deb_lot_ex = 0;
		}
		Debug_WinUpdate(wk);
		return;
	}
	if(sys.trg & PAD_BUTTON_Y){
		if(wk->bonus_game_f || wk->deb_lot_basic == 0){
			return;
		}
		Snd_SePlay(SEQ_SE_DP_SELECT);
		if(wk->deb_lot_basic < 5){
			wk->deb_lot_ex = (wk->deb_lot_ex+1)%4;
		}else{
			wk->deb_lot_ex = (wk->deb_lot_ex+1)%3;
		}
		Debug_WinUpdate(wk);
		return;
	}
	if((sys.cont & PAD_BUTTON_L) && (sys.trg & PAD_BUTTON_START)){
		wk->deb_play_ct = 0;
		MI_CpuClear8(wk->deb_lot_ct,sizeof(int)*PRIZE_CODE_MAX*2);
		Debug_WinUpdate(wk);
		return;
	}
	if((sys.cont & PAD_BUTTON_R) && (sys.trg & PAD_BUTTON_START)){
		wk->deb_auto_f = TRUE;
		wk->deb_auto_ct = 0;
		return;
	}
	if((sys.trg & PAD_BUTTON_START)){
		wk->stress_ct = 0;
		Debug_WinUpdate(wk);
		return;
	}
}

void Debug_WinUpdate(SLOTMAIN* wk)
{
	if(!wk->deb_print_f){
		return;
	}
	//プライズ抽選結果
	{
		WORDSET_RegisterNumber( wk->msg.wset, 0,
			wk->lot_basic+1 , 1, NUMBER_DISPTYPE_ZERO, NUMBER_CODETYPE_ZENKAKU );
		WORDSET_RegisterNumber( wk->msg.wset, 1,
			wk->lot_ex+1 , 1, NUMBER_DISPTYPE_ZERO, NUMBER_CODETYPE_HANKAKU );
		WORDSET_RegisterNumber( wk->msg.wset, 2,
			wk->deb_lot_basic , 1, NUMBER_DISPTYPE_ZERO, NUMBER_CODETYPE_ZENKAKU );
		WORDSET_RegisterNumber( wk->msg.wset, 3,
			wk->deb_lot_ex , 1, NUMBER_DISPTYPE_ZERO, NUMBER_CODETYPE_HANKAKU );
		//難易度
		WORDSET_RegisterNumber( wk->msg.wset, 4,
			wk->hard, 1, NUMBER_DISPTYPE_LEFT, NUMBER_CODETYPE_HANKAKU );
		debug_WinLinePut(wk,0,0,1,msg_deb_prize);
	}

	//プレイ回数＆ストレス値
	{
		WORDSET_RegisterNumber( wk->msg.wset, 0,
			wk->deb_play_ct , 10, NUMBER_DISPTYPE_LEFT, NUMBER_CODETYPE_HANKAKU );
		//連荘
		WORDSET_RegisterNumber( wk->msg.wset, 2,
			wk->consec_win , 2, NUMBER_DISPTYPE_ZERO, NUMBER_CODETYPE_HANKAKU );

		if(wk->stress_ct >= 0){
			WORDSET_RegisterNumber( wk->msg.wset, 1,
				wk->stress_ct , 3, NUMBER_DISPTYPE_LEFT, NUMBER_CODETYPE_HANKAKU );
			debug_WinLinePut(wk,0,1,1,msg_deb_stress01);
		}else{
			WORDSET_RegisterNumber( wk->msg.wset, 1,
				wk->stress_ct*-1 , 3, NUMBER_DISPTYPE_LEFT, NUMBER_CODETYPE_HANKAKU );
			debug_WinLinePut(wk,0,1,1,msg_deb_stress02);
		}
	}

	{	//抽選結果カウント
		int i;

		for(i = 0;i < PRIZE_CODE_MAX;i++){
			WORDSET_RegisterNumber( wk->msg.wset, i*2+0,
				wk->deb_lot_ct[i][0] , 4, NUMBER_DISPTYPE_ZERO, NUMBER_CODETYPE_HANKAKU );
			WORDSET_RegisterNumber( wk->msg.wset, i*2+1,
				wk->deb_lot_ct[i][1] , 5, NUMBER_DISPTYPE_ZERO, NUMBER_CODETYPE_HANKAKU );
		}
		debug_WinLinePut(wk,76,2,3,msg_deb_ct01);
		debug_WinLinePut(wk,152,5,1,msg_deb_ct02);
	}
	GF_BGL_BmpWinOnVReq(&wk->deb_win);
}

void Debug_LotterySet(SLOTMAIN* wk)
{
	wk->deb_play_ct++;
	wk->deb_lot_ct[wk->lot_basic][1]++;
}

void Debug_WinResultSet(SLOTMAIN* wk)
{
	wk->deb_lot_ct[wk->win_code][0]++;
	Debug_WinUpdate(wk);
}

static void debug_WinLinePut(SLOTMAIN* wk,u8 px,u8 py,u8 sy,u8 msg_idx)
{
	py = py*2*8;
	sy = sy*2*8;

	MSGMAN_GetString(wk->msg.man,msg_idx,wk->msg.tmp);
	WORDSET_ExpandStr( wk->msg.wset, wk->msg.str ,wk->msg.tmp);

	GF_BGL_BmpWinFill( &wk->deb_win, 0, 0, py, BMP_DEB_SX*8, sy);
	GF_STR_PrintColor( &wk->deb_win, FONT_SYSTEM, wk->msg.str,
		px,py, MSG_NO_PUT, GF_PRINTCOLOR_MAKE(0x2,0x3,0xF) , NULL );
}

#endif	//PM_DEBUG
//デバッグ
///////////////////////////////////////////////////////////////////////////